/*
 * Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
 *
 * Licensed under the Mulan PSL v2.
 * You can use this file according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of the License at
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
 * FOR MORE DETAILS.
 */

#pragma once

#include <unordered_set>

#include "IDatabaseHub.h"

SG_DBMANAGER_NAMESPACE_OPEN

class DBServiceFactory;
class DataOperate;

/**
 * @class IDatabase
 * @brief 抽象类，管理数据库的基本操作和存储库。
 *
 * IDatabase 类提供了基本的数据库操作接口，包括清除和保存数据库的方法。
 * 还提供了获取和更新数据存储库的功能。
 */
class DBManager_DECLSPEC IDatabase
{
  public:
    /**
     * @brief 构造函数，使用文件路径和文件名初始化数据库。
     * @param foldPath 数据库文件的路径。
     * @param fileName 数据库文件的名称。
     */
    IDatabase (std::uint8_t databaseType, std::string foldPath, std::string fileName);
    IDatabase (const IDatabase& other)            = delete;
    IDatabase& operator= (const IDatabase& other) = delete;

    /**
     * @brief 析构函数，虚函数确保子类正确析构。
     */
    virtual ~IDatabase ();

    /**
     * @brief 清除数据库，纯虚函数，子类必须实现。
     */
    virtual void ClearDatabase () = 0;

    /**
     * @brief 保存数据库，纯虚函数，子类必须实现。
     */
    virtual void SaveDatabase () = 0;

    /**
     * @brief 断开数据库连接，纯虚函数，子类必须实现。
     */
    virtual void Disconnect () = 0;

    /**
     * @brief 连接该数据库
     */
    virtual void Connect () = 0;

    void SetPartitionElement (std::vector<SG::DataStructure::Common::Id> elementIds)
    {
        std::unordered_set<SG::DataStructure::Common::Id> uniqueIds (elementIds.begin (), elementIds.end ());
        m_partitionElementMap = std::move (uniqueIds);
        if (m_partitionElementMap.size () > 0)
        {
            m_isFilter = true;
        }
        else
        {
            m_isFilter = false;
        }
    }

    const std::unordered_set<SG::DataStructure::Common::Id>& GetPartitionElement () const
    {
        return m_partitionElementMap;
    }

    const bool& GetPartitionisFilter () const
    {
        return m_isFilter;
    }

    void ClearPartitionElement ()
    {
        m_partitionElementMap.clear ();
        m_isFilter = false;
    }

    /**
     * @brief 获取指定类型的数据存储库。
     * @tparam T 数据存储库的类型。
     * @return 指向数据存储库的共享指针，如果存储库不存在则返回 nullptr。
     */
    template <class T>
    std::shared_ptr<T> GetRepository ()
    {
        if (UpdataRepository (typeid (T)) == SG::DataStructure::Common::Status::STATUS_Success)
        {
            return std::static_pointer_cast<T> (m_dataRepositories[typeid (T).hash_code ()]);
        }
        assert (false);
        return nullptr;
    }

    std::string GetFileName () const
    {
        return m_fileName;
    }
    std::string GetFoldPath () const
    {
        return m_foldPath;
    }
    std::string GetFullpath () const
    {
        return m_fullpath;
    }
    std::uint8_t GetDatabaseType () const
    {
        return m_databaseType;
    }

    /**
     * @brief 获取仓库指针
     * @return 仓库指针
     */
    void* GetDataRepositorieP (std::size_t RepKey) const;

    std::map<std::size_t, std::shared_ptr<void>>& GetDataRepositories ()
    {
        return m_dataRepositories;
    }

    /**
     * @brief 获取 IDatabaseHub 对象
     * @return IDatabaseHub 对象
     */
    IDatabaseHub* GetHub ()
    {
        return m_hubptr;
    }

    DataOperate& GetDataOperate ()
    {
        return *m_dataOperate;
    }

  protected:
    /**
     * @brief 创建指定类型的数据存储库，纯虚函数，子类必须实现。
     * @param typeInfo 存储库类型的信息。
     * @return 如果创建成功则返回 true，否则返回 false。
     */
    virtual SG::DataStructure::Common::Status CreateRepository (const std::type_info& typeInfo) = 0;

  public:
    /**
     * @brief 更新数据存储库，如果存储库不存在则创建它。
     * @param typeInfo 存储库类型的信息。
     * @return 如果更新成功则返回 true，否则返回 false。
     */
    SG::DataStructure::Common::Status UpdataRepository (const std::type_info& typeInfo);

  private:
    std::uint8_t m_databaseType = 0;  ///< 数据库类型，可以是 MEMORY 或 HDF5。
    std::string  m_fileName;          ///< 数据库文件的名称，例如 "data.db"。
    std::string  m_foldPath;          ///< 数据库文件的路径，不包含文件名，例如 "/home/user/data"。
    std::string  m_fullpath;          ///< 数据库文件的完整路径，包括路径和文件名，例如 "/home/user/data/data.db"。
    DataOperate* m_dataOperate;       ///< 数据操作对象，用于统一数据操作接口。

    std::map<std::size_t, std::shared_ptr<void>> m_dataRepositories;  ///< 数据存储库的映射表，将类型哈希值与对应的数据存储库共享指针关联。

    std::unordered_set<SG::DataStructure::Common::Id> m_partitionElementMap;  // 当前分区的单元ID列表
    bool                                              m_isFilter = false;     ///< 是否进行ID过滤

  protected:
    IDatabaseHub* m_hubptr = nullptr;                                         ///< IDatabaseHub 对象，用于管理信号和槽。
};

/**
 * @brief 类型到Repository的映射模板特化
 * 使用类模板特化自动映射数据类型到对应的Repository接口
 */
// template <SG::DataStructure::FEM::ElementTypes ElementType>
// struct RepositoryTypeMap
// {
//     using RepositoryType = void;  ///< 默认类型为 void，表示未定义
// };

class DBManager_DECLSPEC DataOperate
{
  public:
    DataOperate (IDatabase* database) : m_database (database)
    {
        assert (m_database != nullptr);
    }

  public:
    // template <SG::DataStructure::FEM::ElementTypes TDataType>
    // std::shared_ptr<typename RepositoryTypeMap<TDataType>::RepositoryType> GetElementRepository ()
    // {
    //     using rt = typename RepositoryTypeMap<TDataType>::RepositoryType;
    //     return m_database->GetRepository<rt> ();
    // }

    /**
     * @brief 统一的Element数据添加接口
     * @tparam TDataType Element数据类型(如CQUAD4Data, CBARData等)
     * @param data 要添加的Element数据
     * @return 操作状态
     * @author wuxingchuang
     * @date 2025.07.30
     */
    template <typename TDataType>
    SG::DataStructure::Common::Status Add (TDataType& data);

    /**
     * @brief 统一的Element数据批量添加接口
     * @tparam TDataType Element数据类型(如CQUAD4Data, CBARData等)
     * @param data 要添加的Element数据
     * @return 操作状态
     * @author wuxingchuang
     * @date 2025.07.31
     */
    template <typename TDataType>
    SG::DataStructure::Common::Status MultiAdd (TDataType& data);

    /**
     * @brief 根据索引查找Element数据
     * @tparam TDataType Element数据类型
     * @param index 索引
     * @param entity 输出的Entity数据
     * @return 操作状态
     * @author wuxingchuang
     * @date 2025.07.31
     */
    template <typename TDataType>
    SG::DataStructure::Common::Status FindByIndex (std::size_t index, TDataType& entity);

    /**
     * @brief 根据ID查找Element数据
     * @tparam TDataType Element数据类型
     * @param id 数据ID
     * @param entity 输出的Entity数据
     * @return 操作状态
     * @author wuxingchuang
     * @date 2025.07.31
     */
    template <typename TDataType>
    SG::DataStructure::Common::Status FindById (SG::DataStructure::Common::Id id, TDataType& entity);

    /**
     * @brief 获取指定类型的数据总数
     * @tparam TDataType Element数据类型
     * @return 数据总数
     * @author wuxingchuang
     * @date 2025.07.31
     */
    template <typename TDataType>
    std::size_t Size ();

    /**
     * @brief 获取指定类型的所有数据ID
     * @tparam TDataType Element数据类型
     * @return 所有数据的ID列表
     * @author wuxingchuang
     * @date 2025.07.31
     */
    template <typename TDataType>
    std::vector<SG::DataStructure::Common::Id> GetAllId ();

    /**
     * @brief 获取指定类型的所有数据
     * @tparam TDataType Element数据类型
     * @return 所有数据
     * @author wuxingchuang
     * @date 2025.07.31
     */
    template <typename TDataType>
    std::vector<TDataType> GetAllData ();

    /**
     * @brief 获取指定ID的数据数量
     * @tparam TDataType Element数据类型
     * @param id 数据ID
     * @return 数据数量
     * @author wuxingchuang
     * @date 2025.07.31
     */
    template <typename TDataType>
    std::size_t Count (SG::DataStructure::Common::Id id);

    /**
     * @brief    Get the Element Node Size
     *
     * @tparam TDataType
     * @return
     * @author   wuxingchuang
     * @date     2025.07.31
     */
    template <typename TDataType>
    std::size_t GetElementNodeSize ();

  private:
    IDatabase* m_database = nullptr;  ///< 当前用到的数据库
};

SG_DBMANAGER_NAMESPACE_CLOSE
